<?php

declare(strict_types = 1);

namespace App\Test\Fixtures;

use App\Core\ActorLocalRoles;
use App\Core\VisibilityScope;
use App\Entity\Activity;
use App\Entity\Actor;
use App\Entity\LocalUser;
use App\Entity\Note;
use Component\Conversation\Conversation;
use Component\Group\Entity\GroupMember;
use Component\Group\Entity\LocalGroup;
use Component\Language\Entity\Language;
use Component\Notification\Entity\Attention;
use Component\Notification\Entity\Notification;
use Component\Subscription\Entity\ActorSubscription;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Intl\Locales;

class CoreFixtures extends Fixture
{
    public function load(ObjectManager $manager)
    {
        // Populate Initial Language values
        foreach (Locales::getNames() as $key => $name) {
            $manager->persist(Language::create(['locale' => $key, 'short_display' => $key, 'long_display' => $name]));
        }
        $manager->flush();

        $actors         = [];
        $local_entities = [];
        foreach ([
            'taken_user' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'taken_user@provider.any'],
                ['roles'    => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'some_user' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'some_user@provider.any'],
                ['roles'    => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'admin' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'admin@provider.any'],
                ['roles'    => ActorLocalRoles::OPERATOR | ActorLocalRoles::MODERATOR | ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'local_user_test_user' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'local_user_test_user@provider.any'],
                ['roles'    => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'form_personal_info_test_user' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'form_personal_info_test_user@provider.any'],
                ['roles'    => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'form_account_test_user' => [
                LocalUser::class,
                'setId',
                ['password' => LocalUser::hashPassword('foobar'), 'outgoing_email' => 'form_account_test_user@provider.any'],
                ['roles'    => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
            'taken_public_group' => [
                LocalGroup::class,
                'setActorId',
                [],
                ['roles' => ActorLocalRoles::VISITOR, 'type' => Actor::GROUP],
            ],
            'taken_private_group' => [
                LocalGroup::class,
                'setActorId',
                [],
                ['roles' => ActorLocalRoles::VISITOR | ActorLocalRoles::PRIVATE_GROUP, 'type' => Actor::GROUP],
            ],
            'local_user_note_test' => [
                LocalUser::class,
                'setId',
                [],
                ['roles' => ActorLocalRoles::PARTICIPANT | ActorLocalRoles::VISITOR, 'type' => Actor::PERSON],
            ],
        ] as $nick => [$entity, $method, $extra_create, $extra_create_actor]) {
            $actor = Actor::create(array_merge(['nickname' => $nick, 'is_local' => true], $extra_create_actor));
            $manager->persist($actor);
            // cannot use array spread for arrays with string keys
            $ent = $entity::create(array_merge(['nickname' => $nick], $extra_create));
            $ent->{$method}($actor->getId());
            $local_entities[$nick] = $ent;
            $manager->persist($ent);
            // Add self subscriptions
            $manager->persist(ActorSubscription::create(['subscriber_id' => $actor->getId(), 'subscribed_id' => $actor->getId()]));
            $actors[$nick] = $actor;
        }

        $notes   = [];
        $notes[] = Note::create(['actor_id' => $actors['taken_user']->getId(), 'content' => 'some other content', 'content_type' => 'text/plain', 'is_local' => true]);
        $notes[] = Note::create(['actor_id' => $actors['taken_user']->getId(), 'content' => 'private note', 'scope' => VisibilityScope::MESSAGE, 'content_type' => 'text/plain', 'is_local' => false]);
        $notes[] = Note::create(['actor_id' => $actors['local_user_note_test']->getId(), 'content' => 'message', 'scope' => VisibilityScope::MESSAGE, 'content_type' => 'text/plain', 'is_local' => false]);
        $notes[] = Note::create(['actor_id' => $actors['local_user_note_test']->getId(), 'content' => 'some other content', 'content_type' => 'text/plain', 'is_local' => false]);
        foreach ($notes as $note) {
            $manager->persist($note);
            $activity = Activity::create(['actor_id' => $actors['taken_user']->getId(), 'verb' => 'create', 'object_type' => 'note', 'object_id' => $note->getId(), 'source' => 'auto-test']);
            Conversation::assignLocalConversation($note, null);
            $manager->persist($activity);
        }

        $group_notes   = [];
        $group_notes[] = $public_group_note = Note::create(['actor_id' => $actors['taken_user']->getId(), 'content' => 'group note public', 'scope' => VisibilityScope::EVERYWHERE, 'content_type' => 'text/plain', 'is_local' => true]);
        $group_notes[] = $private_group_note = Note::create(['actor_id' => $actors['local_user_note_test']->getId(), 'content' => 'group note private', 'scope' => VisibilityScope::GROUP, 'content_type' => 'text/plain', 'is_local' => true]);
        foreach ($group_notes as $note) {
            $manager->persist($note);
            $activity = Activity::create(['actor_id' => $actors['taken_user']->getId(), 'verb' => 'create', 'object_type' => 'note', 'object_id' => $note->getId(), 'source' => 'auto-test']);
            Conversation::assignLocalConversation($note, null);
            $manager->persist($activity);
            $manager->persist(Notification::create(['activity_id' => $activity->getId(), 'target_id' => $local_entities['taken_public_group']->getActorId(), 'reason' => 'testing']));
            $manager->persist(Notification::create(['activity_id' => $activity->getId(), 'target_id' => $local_entities['taken_private_group']->getActorId(), 'reason' => 'testing']));
        }

        $manager->persist(Attention::create(['object_type' => Note::schemaName(), 'object_id' => $public_group_note->getId(), 'target_id' => $local_entities['taken_public_group']->getActorId()]));

        $manager->persist(GroupMember::create(['group_id' => $local_entities['taken_private_group']->getActorId(), 'actor_id' => $actors['some_user']->getId()]));
        $manager->persist(Attention::create(['object_type' => Note::schemaName(), 'object_id' => $private_group_note->getId(), 'target_id' => $local_entities['taken_private_group']->getActorId()]));

        $manager->flush();
    }
}
